home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / DB_CLIPP / 0643A.ZIP / DB3TOWP.PAS < prev    next >
Pascal/Delphi Source File  |  1986-08-18  |  22KB  |  755 lines

  1. program dBaseIIIToSPSS;
  2.  
  3. { dBASE III (and +) file handling routines written by
  4.   J. Troutman, Compuserve ID 74746,1567
  5.   File DBF.PAS
  6.   Version 1.1  }
  7.  
  8. {$V-}
  9.  
  10. type RegPack = record
  11.                AX,BX,CX,DX,BP,SI,DI,DS,ES,FLAGS : integer
  12.                end;
  13.      AnyStr = string[255];
  14.  
  15. const
  16.   ProgramTitle = 'dBASE III --> WordPerfect Merge File Conversion Utility';
  17.   DisClaimer1 = 'dBASE III and dBASE III Plus are registered trademarks of Ashton-Tate.';
  18.   DisClaimer2 = 'WordPerfect is a registered trademark of WordPerfect Incorporated.';
  19.   CopyRight =
  20.           'Copyright (C) 1986 by William J. Bliss and Northwestern University';
  21.   Version = 'Version 1.0, July 1986';
  22.  
  23.   DefaultWPExt = 'DAT';
  24.   UpCaseOnly = true;
  25.  
  26.   FieldDelim = ^R#10;
  27.   RecordDelim = ^E#10;
  28.  
  29. type
  30.   DOSFileNameType = string[64];
  31.   ValidSetType = set of char;
  32.  
  33. var
  34.   ControlFile,DataFile : text[4096];
  35.   DOSdBASEFile, DOSWPFile : DOSFileNameType;
  36.   Default : AnyStr;
  37.   DefLen : byte absolute Default;
  38.  
  39.   Choice : char;
  40.   Trim : (Yes, No, Undefined);
  41.  
  42.  
  43. { Constants, type and variable declarations for dBASE conversion }
  44.  
  45.  
  46. CONST
  47.   DB3File = 3;
  48.   DB3WithMemo = $83;
  49.   ValidTypes : SET OF Char = ['C', 'N', 'L', 'M', 'D'];
  50.   MAX_HEADER = 4129;          { = maximum length of dBASE III header }
  51.   MAX_BYTES_IN_RECORD = 4000; { dBASE III record limit }
  52.   MAX_FIELDS_IN_RECORD = 128; { dBASE III field limit  }
  53.   BYTES_IN_MEMO_RECORD = 512; { dBASE III memo field record size }
  54.  
  55. TYPE
  56.   HeaderType = ARRAY[0..MAX_HEADER] OF Byte;
  57.   HeaderPrologType = ARRAY[0..31] OF Byte; { dBASE III header prolog }
  58.   FieldDescType = ARRAY[0..31] OF Byte; { dBASE III field definitions }
  59.   DbfRecord = ARRAY[0..MAX_BYTES_IN_RECORD] OF Byte; { the 0 offset represents
  60.                                                        the 'deleted' flag.   }
  61.   Str255 = STRING[255];
  62.   Str80 = STRING[80];
  63.   Str64 = STRING[64];
  64.   Str10 = STRING[10];
  65.   Str8 = STRING[8];
  66.   Str2 = STRING[2];
  67.   DbfFileType = FILE;
  68.   FieldRecord = RECORD
  69.                   Name : Str10;
  70.                   Typ : Char;
  71.                   Len : Byte;
  72.                   Dec : Byte;
  73.                   Off : Integer;
  74.                 END;
  75.   FieldArray = ARRAY[1..MAX_FIELDS_IN_RECORD] OF FieldRecord;
  76.   MemoRecord = ARRAY[1..BYTES_IN_MEMO_RECORD] OF Byte;
  77.   MemoFileType = FILE OF MemoRecord;
  78.   DbfInfoType = RECORD
  79.                   FileName     : Str64;
  80.                   dFile        : DbfFileType;
  81.                   HeadProlog   : HeaderPrologType;
  82.                   Updated      : Boolean;
  83.                   WithMemo     : Boolean;
  84.                   DateOfUpdate : Str8;
  85.                   NumRecs      : Real;
  86.                   HeadLen      : Integer;
  87.                   RecLen       : Integer;
  88.                   NumFields    : Integer;
  89.                   Fields       : FieldArray;
  90.                   CurRecord    : DbfRecord;
  91.                 END;
  92.  
  93.  
  94. var
  95.   InputFile : DbfInfoType;
  96.  
  97.  
  98. procedure PaintLogo;
  99.  
  100. begin
  101.   ClrScr;
  102.   TextColor(LightBlue); 
  103.   writeln(ProgramTitle,', ',Version); 
  104.   writeln(CopyRight); 
  105.   writeln('All Rights Reserved.');
  106.   TextColor(Yellow); 
  107.   writeln;            
  108.   writeln(Disclaimer1); 
  109.   writeln(Disclaimer2); 
  110.   writeln
  111. end;
  112.  
  113.  
  114. procedure GetChar(var ch : char);
  115.  
  116. var
  117.   registers : RegPack;
  118.   AL,AH: byte;
  119.  
  120. begin
  121.   registers.AX:=$0000;
  122.   Intr($16,registers);
  123.  
  124.   ch := chr(Lo(registers.AX))  { Low order byte of AX }
  125. end;
  126.  
  127.  
  128. procedure WaitFor(ValidSet : ValidSetType;
  129.                   UpperOnly : boolean;
  130.                   var Response : char);
  131.  
  132. begin
  133.   repeat
  134.     GetChar(Response)
  135.   until (UpCase(Response) in ValidSet);
  136.   if UpperOnly then
  137.     write(UpCase(Response))
  138.   else
  139.     write(Response)
  140. end;
  141.  
  142.  
  143. function FileExist(var FileName : DOSFileNameType) : boolean;
  144.  
  145. var
  146.   TempFile : file;
  147.  
  148. begin
  149.   {$I-}
  150.   assign(TempFile,FileName);
  151.   reset(TempFile);
  152.   {$I-}
  153.   FileExist := (IOResult = 0)
  154. end;
  155.  
  156.  
  157. procedure OutputExists(var FileName : DOSFileNameType);
  158.  
  159. var
  160.   TempFile : file;
  161.   Response : char;
  162.  
  163. begin
  164.   writeln('File ',FileName,' already exists.');
  165.   write('Overwrite it or specify Another file (O/A)? ');
  166.   WaitFor(['O','A'],UpCaseOnly,Response);
  167.   writeln;
  168.  
  169.   case UpCase(Response) of
  170.  
  171.        'O' : begin
  172.                assign(TempFile,FileName);
  173.                erase(TempFile)
  174.              end;
  175.  
  176.        'A' : FileName := '';
  177.  
  178.   end  { case }
  179.  
  180. end;
  181.  
  182.  
  183. procedure GetInputFile(var FileName : DOSFileNameType);
  184.  
  185. var
  186.   Continue : boolean;
  187.   i : integer;
  188.  
  189. begin
  190.  
  191.   if not FileExist(FileName) then
  192.     begin
  193.  
  194.       if FileName <> '' then
  195.         begin
  196.           writeln;
  197.           writeln('File ',FileName,' not found.');
  198.           writeln
  199.         end;
  200.  
  201.       repeat
  202.         write('File to convert (d:filename, .DBF assumed, RETURN to quit)? ');
  203.         read(FileName);
  204.         for i := 1 to Length(FileName) do
  205.           FileName[i] := UpCase(FileName[i]);
  206.  
  207.         if (Pos('.',FileName) = 0) and (Length(FileName) > 0) then
  208.           FileName := FileName + '.DBF';
  209.  
  210.         Continue := ((length(FileName) = 0) or FileExist(FileName));
  211.  
  212.         writeln;
  213.         if not Continue then
  214.           begin
  215.             writeln;
  216.             write('Cannot find file ',FileName,'.');
  217.             writeln;
  218.             writeln
  219.           end
  220.  
  221.       until Continue
  222.  
  223.     end;  { if not FileExist(FileName) }
  224.  
  225.   writeln
  226.  
  227. end;
  228.  
  229.  
  230. procedure GetOutputFile(var FileName : DOSFileNameType;
  231.                             Default : AnyStr);
  232.  
  233. var
  234.   Continue : boolean;
  235.   Choice : char;
  236.   Phrase : AnyStr;
  237.   i : integer;
  238.  
  239. begin
  240.   Phrase := 'WordPerfect merge';
  241.  
  242.   if FileName = DOSdBaseFile then
  243.     begin
  244.       writeln;
  245.       write('ERROR: ');
  246.       writeln('The output file cannot be the same as the input file.');
  247.       writeln;
  248.       FileName := ''
  249.     end;
  250.  
  251.   if FileExist(FileName) then
  252.     OutputExists(FileName);
  253.  
  254.   if FileName = '' then
  255.     repeat
  256.       write('Name of ',Phrase,' file (Default = ',Default,')? ');
  257.       read(FileName);
  258.       for i := 1 to Length(FileName) do
  259.         FileName[i] := UpCase(FileName[i]);
  260.       writeln;
  261.       if FileName = '' then
  262.         FileName := Default;
  263.  
  264.       if FileName = DOSdBaseFile then
  265.         begin
  266.           writeln;
  267.           write('ERROR: ');
  268.           writeln('An output file cannot be the same as the input file.');
  269.           writeln;
  270.           FileName := ''
  271.         end;
  272.  
  273.       if FileExist(FileName) then
  274.         OutputExists(FileName)
  275.  
  276.     until length(FileName) <> 0;
  277.  
  278. end;
  279.  
  280.  
  281. (* The routines in this file present some fairly general purpose tools for
  282.    accessing dBASE III and dBASE III Plus files from within a Turbo Pascal
  283.    program.  There is much room for improvement: the error checking is
  284.    rudimentary, no routines to access memo files, no buffering of data,
  285.    no support for index files, etc.
  286.    The main routines are:
  287.  
  288.       FUNCTION OpenDbf(VAR D : DbfInfoType;) : Integer;
  289.       FUNCTION CloseDbf(VAR D : DbfInfoType) : Integer;
  290.       PROCEDURE GetDbfRecord(VAR D : DbfInfoType; RecNum : Real);
  291.  
  292.       A skeletal program would go something like:
  293.         BEGIN
  294.         {...initialize and get filename of .dbf file into FileName field
  295.             of DbfInfoType Record variable ...  }
  296.         IF OpenDbf(...)  { to open the file              }
  297.         {... the rest of your program including calls to
  298.              GetDbfRecord as needed  }
  299.         IF CloseDbf (...) { to close the file            }
  300.         END.
  301.  
  302.       Upon exit from the GetDbfRecord Procedure, the CurRecord field of the
  303.       DbfInfoType variable contains the current record contents.  Each field
  304.       can be accessed using its offset into the CurRecord with the variable
  305.       Off in the Fields array.
  306.  
  307.       See the demo program for some examples.
  308.       While I intend to upload more complete routines and better
  309.       documentation at some time, if you should have any problems with
  310.       these routines, please leave me a note.
  311.  
  312. dBASE III Database File Structure
  313. The structure of a dBASE III database file is composed of a
  314. header and data records.  The layout is given below.
  315. dBASE III DATABASE FILE HEADER:
  316. +---------+-------------------+---------------------------------+
  317. |  BYTE   |     CONTENTS      |          MEANING                |
  318. +---------+-------------------+---------------------------------+
  319. |  0      |  1 byte           | dBASE III version number        |
  320. |         |                   |  (03H without a .DBT file)      |
  321. |         |                   |  (83H with a .DBT file)         |
  322. +---------+-------------------+---------------------------------+
  323. |  1-3    |  3 bytes          | date of last update             |
  324. |         |                   |  (YY MM DD) in binary format    |
  325. +---------+-------------------+---------------------------------+
  326. |  4-7    |  32 bit number    | number of records in data file  |
  327. +---------+-------------------+---------------------------------+
  328. |  8-9    |  16 bit number    | length of header structure      |
  329. +---------+-------------------+---------------------------------+
  330. |  10-11  |  16 bit number    | length of the record            |
  331. +---------+-------------------+---------------------------------+
  332. |  12-31  |  20 bytes         | reserved bytes (version 1.00)   |
  333. +---------+-------------------+---------------------------------+
  334. |  32-n   |  32 bytes each    | field descriptor array          |
  335. |         |                   |  (see below)                    | --+
  336. +---------+-------------------+---------------------------------+   |
  337. |  n+1    |  1 byte           | 0DH as the field terminator     |   |
  338. +---------+-------------------+---------------------------------+   |
  339. |
  340. |
  341. A FIELD DESCRIPTOR:      <------------------------------------------+
  342. +---------+-------------------+---------------------------------+
  343. |  BYTE   |     CONTENTS      |          MEANING                |
  344. +---------+-------------------+---------------------------------+
  345. |  0-10   |  11 bytes         | field name in ASCII zero-filled |
  346. +---------+-------------------+---------------------------------+
  347. |  11     |  1 byte           | field type in ASCII             |
  348. |         |                   |  (C N L D or M)                 |
  349. +---------+-------------------+---------------------------------+
  350. |  12-15  |  32 bit number    | field data address              |
  351. |         |                   |  (address is set in memory)     |
  352. +---------+-------------------+---------------------------------+
  353. |  16     |  1 byte           | field length in binary          |
  354. +---------+-------------------+---------------------------------+
  355. |  17     |  1 byte           | field decimal count in binary   |
  356. +---------+-------------------+--------------------------------
  357. |  18-31  |  14 bytes         | reserved bytes (version 1.00)   |
  358. +---------+-------------------+---------------------------------+
  359. The data records are layed out as follows:
  360. 1. Data records are preceeded by one byte that is a
  361. space (20H) if the record is not deleted and an
  362. asterisk (2AH) if it is deleted.
  363. 2. Data fields are packed into records with no field
  364. separators or record terminators.
  365. 3. Data types are stored in ASCII format as follows:
  366. DATA TYPE      DATA RECORD STORAGE
  367. ---------      --------------------------------------------
  368. Character      (ASCII characters)
  369. Numeric        - . 0 1 2 3 4 5 6 7 8 9
  370. Logical        ? Y y N n T t F f  (? when not initialized)
  371. Memo           (10 digits representing a .DBT block number)
  372. Date           (8 digits in YYYYMMDD format, such as
  373.                 19840704 for July 4, 1984)
  374.  
  375. This information came directly from the Ashton-Tate Forum.
  376. It can also be found in the Advanced Programmer's Guide available
  377. from Ashton-Tate.
  378. *)
  379.  
  380.  
  381.   (*
  382.   Notice that if you need to access more than one .DBF file simultaneously
  383.   you could declare ARRAYs of DbfFileType, DbfInfoType, etc.
  384.   *)
  385.  
  386.   PROCEDURE ErrorHalt(Msg : Str80);
  387.  
  388.   BEGIN
  389.   WriteLn;
  390.   WriteLn(Msg);
  391.   Halt;
  392.   END;
  393.  
  394.   FUNCTION MakeReal(VAR b) : Real;
  395.   VAR
  396.     r : ARRAY[1..4] OF Byte ABSOLUTE b;
  397.  
  398.   BEGIN
  399.     MakeReal := (r[1]*1)+(r[2]*256)+(r[3]*65536.0)+(r[4]*16777216.0);
  400.   END;
  401.  
  402.   FUNCTION MakeInt(VAR b) : Integer;
  403.   VAR
  404.     i : Integer ABSOLUTE b;
  405.  
  406.   BEGIN
  407.     MakeInt := i;
  408.   END;
  409.  
  410.   FUNCTION MakeStr(b : Byte) : Str2;
  411.   VAR
  412.     i : Integer;
  413.     s : Str2;
  414.   BEGIN
  415.     i := b;
  416.     Str(i:2, s);
  417.     MakeStr := s;
  418.   END;
  419.  
  420.  
  421.   PROCEDURE UpdateHeader(VAR D : DbfInfoType);
  422.  
  423.   TYPE
  424.     RegType  = Record  Case Integer of
  425.                  1 : (AX,BX,CX,DX,BP,SI,DI,DS,ES,Flags: Integer);
  426.                  2 : (AL,AH,BL,BH,CL,CH,DL,DH : Byte);
  427.                END;
  428.  
  429.   VAR
  430.     Reg : RegType;
  431.     r : Real;
  432.  
  433.  
  434.   BEGIN
  435.   WITH D DO
  436.     BEGIN
  437.       Reg.AX := $2A00;  { Get DOS Date }
  438.       Intr ($21,Reg);
  439.       HeadProlog[1] := Reg.CX - 1900; {Year}
  440.       HeadProlog[2] := Reg.DH;        {Month}
  441.       HeadProlog[3] := Reg.DL;        {Day}
  442.       r := NumRecs;
  443.       HeadProlog[7] := Trunc(r / 16777216.0);
  444.       r := r - (HeadProlog[7] * 16777216.0);
  445.       HeadProlog[6] := Trunc(r / 65536.0);
  446.       r := r - (HeadProlog[6] * 65536.0);
  447.       HeadProlog[5] := Trunc(r / 256);
  448.       r := r - (HeadProlog[5] * 256);
  449.       HeadProlog[4] := Trunc(r);
  450.       LongSeek(dFile,0);
  451.       {$I-} BlockWrite(dFile,HeadProlog,SizeOf(HeadProlog)); {$I+}
  452.       IF IOResult <> 0 THEN ErrorHalt('Error Closing file.');
  453.     END; {WITH}
  454.   END;
  455.  
  456.  
  457.   FUNCTION CloseDbf(VAR D : DbfInfoType) : Integer;
  458.   VAR
  459.     b : Byte;
  460.  
  461.   BEGIN
  462.   WITH D DO
  463.     BEGIN
  464.     IF Updated THEN
  465.       BEGIN
  466.         UpdateHeader(D);
  467.         b := $1A;
  468.         LongSeek(dFile,HeadLen+NumRecs*RecLen);
  469.         BlockWrite(dFile,b,1); {Put EOF marker }
  470.       END;
  471.     {$I-} Close(dFile);             {$I+}
  472.     CloseDbf := IOResult;
  473.     END; {WITH}
  474.   END;
  475.  
  476.   PROCEDURE ProcessHeader(VAR Header : HeaderType;
  477.                           VAR D : DbfInfoType);
  478.  
  479.     PROCEDURE GetOneFieldDesc(VAR F; VAR Field : FieldRecord;
  480.                               VAR Offset : Integer);
  481.  
  482.     VAR
  483.       i : Integer;
  484.       FD : FieldDescType ABSOLUTE F;
  485.  
  486.     BEGIN
  487.     WITH Field DO
  488.       BEGIN
  489.         i := 0;
  490.         Name := '          ';
  491.       REPEAT
  492.         Name[Succ(i)] := Chr(FD[i]);
  493.         i := Succ(i);
  494.       UNTIL FD[i] = 0;
  495.       Name[0] := Chr(i);
  496.       Typ := Char(FD[11]);
  497.       Len := FD[16];
  498.       Dec := FD[17];
  499.       Off := Offset;
  500.       Offset := Offset+Len;
  501.       IF NOT(Typ IN ValidTypes) THEN
  502.         ErrorHalt('Invalid Type in Field '+Name);
  503.       END;                    {WITH}
  504.     END;                      {GetOneFieldDesc}
  505.  
  506.  
  507.   VAR
  508.     o, i : Integer;
  509.  
  510.   BEGIN                       {ProcessHeader}
  511.   WITH D DO
  512.     BEGIN
  513.     CASE Header[0] OF
  514.       DB3File : WithMemo := False;
  515.       DB3WithMemo : WithMemo := True;
  516.     ELSE
  517.       ErrorHalt('Not a valid dBASE III File.');
  518.     END;                      {CASE}
  519.     DateOfUpdate := MakeStr(Header[2])+'/'+MakeStr(Header[3])+'/'
  520.                     +MakeStr(Header[1]);
  521.     NumRecs := MakeReal(Header[4]);
  522.     HeadLen := MakeInt(Header[8]);
  523.     RecLen := MakeInt(Header[10]); { Includes the Deleted Record Flag }
  524.     Updated := FALSE;
  525.     NumFields := 0;
  526.     FOR i := 0 TO SizeOf(HeadProlog) DO
  527.       HeadProlog[i] := Header[i];
  528.     o := 1;                   {Offset within dbf record of current field }
  529.     i := 32;                  {Index for Header }
  530.     WHILE Header[i] <> $0D DO
  531.       BEGIN
  532.         NumFields := Succ(NumFields);
  533.         GetOneFieldDesc(Header[i], Fields[NumFields], o);
  534.         i := i+32;
  535.       END;                    {While}
  536.     IF Header[Succ(HeadLen)] = 0 THEN
  537.       HeadLen := Succ(HeadLen);
  538.     END;                      {With}
  539.   END;                        {ProcessHeader}
  540.  
  541.   PROCEDURE GetHeader(VAR D : DbfInfoType);
  542.  
  543.   VAR
  544.     Result : Integer;
  545.     H      : HeaderType;
  546.  
  547.   BEGIN
  548.   WITH D DO
  549.     BEGIN
  550.     {$I-} BlockRead(dFile, H, MAX_HEADER, Result); {$I+}
  551.     IF IOResult <> 0 THEN
  552.       ErrorHalt('Error reading header.');
  553.       ProcessHeader(H, D);
  554.     END; {WITH}
  555.   END;
  556.  
  557.   FUNCTION OpenDbf(VAR D : DbfInfoType) : Integer;
  558.  
  559.   BEGIN
  560.   WITH D DO
  561.     BEGIN
  562.     Assign(dFile, FileName);
  563.     {$I-} Reset(dFile, 1); {$I+}    {the '1' parameter sets the record size}
  564.     IF IOResult <> 0 THEN
  565.       ErrorHalt('Error opening data file.');
  566.       GetHeader(D);
  567.       OpenDbf := IOResult;
  568.     END; {WITH}
  569.   END;
  570.  
  571.  
  572.   PROCEDURE GetDbfRecord(VAR D : DbfInfoType; RecNum : Real);
  573.  
  574.   VAR
  575.     Result : Integer;
  576.  
  577.   BEGIN
  578.   WITH D DO
  579.     BEGIN
  580.     IF RecNum > NumRecs THEN
  581.       ErrorHalt('Tried to read past EOF.');
  582.     LongSeek(dFile, HeadLen+(RecNum-1)*RecLen);
  583.     BlockRead(dFile, CurRecord, RecLen, Result);
  584.     IF Result <> RecLen THEN
  585.       ErrorHalt('Error reading DBF File');
  586.     END;                      { WITH }
  587.   END;                        {GetDbfRecord}
  588.  
  589.  
  590. PROCEDURE CreateData(VAR D : DbfInfoType);
  591.  
  592. var
  593.   r,i : integer;
  594.  
  595.     PROCEDURE WriteField(VAR a; VAR F : FieldRecord);
  596.  
  597.     VAR
  598.       Data : array [1..255] of char ABSOLUTE a;
  599.       Start,TempLen : integer;
  600.  
  601.     BEGIN
  602.       WITH F DO
  603.         BEGIN
  604.           CASE Typ OF
  605.             'N' : begin
  606.                     Start := 1;
  607.                     while Data[Start] = ' ' do
  608.                       Start := Start + 1;
  609.                     write(DataFile,Copy(Data,Start,Len))
  610.                   end;
  611.  
  612.             'C',
  613.             'L' : begin
  614.                     TempLen := Len;
  615.                     if Trim = Yes then
  616.                       while Data[TempLen] = ' ' do
  617.                         TempLen := TempLen - 1;
  618.                       write(DataFile,Copy(Data, 1, TempLen));
  619.                   end;
  620.             'M' : ;
  621.             'D' : write(DataFile,Copy(Data, 5, 2), '/',
  622.                   Copy(Data, 7, 2), '/',
  623.                   Copy(Data, 1, 2));
  624.           END;                    {CASE}
  625.         end;                    {WITH F}
  626.       END;                      { WriteField }
  627.  
  628.  
  629. BEGIN   { CreateData }
  630.  
  631.   WITH D DO
  632.     BEGIN
  633.       r := 1;
  634.       write(r:5,' records written to WordPerfect merge file...');
  635.       WHILE r <= NumRecs DO
  636.         BEGIN
  637.           GotoXY(1,WhereY);
  638.           write(r:5);
  639.           GetDbfRecord(D, r);
  640.           FOR i := 1 TO NumFields DO
  641.             begin
  642.               WriteField(CurRecord[Fields[i].Off], Fields[i]);
  643.               write(DataFile,FieldDelim)
  644.             end;
  645.           write(DataFile,RecordDelim);
  646.           r := r+1
  647.         END;                { WHILE r    }
  648.     END;                    { WITH D     }
  649.   GotoXY(1,WhereY);
  650.   ClrEOL;
  651.   writeln((r-1):5,' records written to WordPerfect merge file ',DOSWPFile,'.')
  652. END;                        { CreateData }
  653.  
  654.  
  655. begin
  656.   DOSdBaseFile := ParamStr(1);
  657.   if DOSdBaseFile = '?' then
  658.     begin
  659.       ClrScr;
  660.       writeln(ProgramTitle);
  661.       writeln;
  662.       TextColor(LightBlue);
  663.       writeln('Usage: DB3WP dBaseFile[.DBF] MergeFile[.DAT] Y/N');
  664.       TextColor(Yellow);
  665.       writeln('               ',#24,'               ',#24,'              ',#24);
  666.       writeln('             dBASE III or    WordPerfect     Trim trailing');
  667.       writeln('             dBASE III +     Secondary       blanks from');
  668.       writeln('             input file      Merge file      character fields');
  669.       writeln;
  670.       writeln('You may specify an asterisk ("*") as the filename for the MergeFile.');
  671.       writeln('This will create a merge file with a filename the same as the .DBF');
  672.       writeln('file but with the appropriate extension (.DAT).');
  673.       writeln;
  674.       writeln('Example: DB3WP ADDRESS.DBF ADDRESS.DAT Y');
  675.       writeln('Result:  Creates ADDRESS.DAT from ADDRESS.DBF; trims trailing blanks');
  676.       writeln('         from character fields.');
  677.       writeln;
  678.       writeln('Example: DB3SPSS ADDRESS * N');
  679.       writeln('Result:  Same as above, but does not trim trailing blanks.');
  680.       writeln;
  681.       writeln('If you simply type DB3WP alone, you will be prompted for each file name and');
  682.       writeln('whether or not you wish to trim trailing blanks from character fields.');
  683.       Halt
  684.    end;
  685.  
  686.   DOSWPFile := ParamStr(2);
  687.  
  688.   if ParamStr(3) = '' then
  689.     Trim := Undefined
  690.   else
  691.     case UpCase(Copy(ParamStr(3),1,1)) of
  692.       'Y' : Trim := Yes;
  693.       'N' : Trim := No
  694.     else
  695.       Trim := Undefined
  696.     end;
  697.  
  698.   if (DOSdBaseFile <> '') and (Pos('.',DOSdBaseFile) = 0) then
  699.     DOSdBaseFile := DOSdBaseFile + '.DBF';
  700.  
  701.   if (ParamCount < 1) or FileExist(DOSWPFile) then
  702.     PaintLogo;
  703.  
  704.   GetInputFile(DOSdBaseFile);
  705.   if length(DOSdBaseFile) = 0 then
  706.     halt;
  707.  
  708.   Default := DOSdBaseFile;
  709.   while Default[DefLen] <> '.' do
  710.     DefLen := Pred(DefLen);
  711.  
  712.   if DOSWPFile = '*' then
  713.     DOSWPFile := Default + DefaultWPExt;
  714.  
  715.   GetOutputFile(DOSWPFile,Default + DefaultWPExt);
  716.  
  717.   if Trim = Undefined then
  718.     begin
  719.       writeln;
  720.       write('Trim trailing blanks of character fields (Y/N)? Y');
  721.       GotoXY(WhereX-1,WhereY);
  722.       repeat
  723.         GetChar(Choice)
  724.       until UpCase(Choice) in ['Y','N',#13];
  725.       case UpCase(Choice) of
  726.         'Y',#13 : Trim := Yes;
  727.         'N'     : begin
  728.                     write('N');
  729.                     Trim := No
  730.                   end
  731.       end
  732.     end;
  733.  
  734.   InputFile.FileName := DOSdBaseFile;
  735.  
  736.   if OpenDBF(InputFile) <> 0 then
  737.     ErrorHalt('Error in opening file '+DOSdBaseFile);
  738.  
  739.   assign(DataFile,DOSWPFile);
  740.   rewrite(DataFile);
  741.  
  742.   PaintLogo;
  743.  
  744.   writeln('Generating data file ',DOSWPFile,' from ',DOSdBaseFile);
  745.  
  746.   CreateData(InputFile);
  747.  
  748.   LowVideo;
  749.   if CloseDbf(InputFile) <> 0 then
  750.     writeln('Error closing ',DOSdBaseFile);
  751.   Close(DataFile);
  752.   writeln
  753.  
  754. end.
  755.